package me.pppploi8.webmcs.main.tools;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import org.apache.commons.compress.archivers.ArchiveEntry;
import org.apache.commons.compress.archivers.sevenz.SevenZFile;
import org.apache.commons.compress.archivers.sevenz.SevenZOutputFile;
import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream;
import org.apache.commons.compress.utils.IOUtils;

import me.pppploi8.webmcs.main.tools.compress.CompressEntry;
import me.pppploi8.webmcs.main.tools.compress.CompressInputStream;
import me.pppploi8.webmcs.main.tools.compress.impl.SevenZInputStream;
import me.pppploi8.webmcs.main.tools.compress.impl.ZipInputStream;

public abstract class CompressUtils {
	/**
	 * 通用解压方法，基于commons-comress，支持zip和7z格式的压缩包
	 * @param file    待解压文件
	 * @param destDir 目标文件夹
	 * @return
	 * @throws IOException
	 */
	public static boolean unCompress(File file, File destDir) throws IOException{
		String fileName = file.getName().toLowerCase();
		if (fileName.endsWith(".zip")){
			unZip(file, destDir);
		} else if (fileName.endsWith(".7z")){
			unSevenZ(file, destDir);
		} else {
			return false;
		}
		return true;
	}
	/**
	 * 7z压缩方法，基于Apache Commons-compress工具
	 * @param dir[] 待压缩的文件数组，支持目录或者文件
	 * @param outputFile 输出压缩文件
	 * @throws IOException 
	 */
	public static void compressToSevenZ(File[] dir, File outputFile) throws IOException{
		SevenZOutputFile szout = new SevenZOutputFile(outputFile);
		for(File f : dir){
			if (f.exists()){
				sevenZCompressFile(szout, f, "");
			}
		}
		szout.close();
	}

	private static void sevenZCompressFile(SevenZOutputFile szout, File f, String dir) throws IOException{
		if (f.isFile()){
			ArchiveEntry entry = szout.createArchiveEntry(f, dir + f.getName());
			szout.putArchiveEntry(entry);
			InputStream is = new FileInputStream(f);
			byte[] bytes = new byte[4096];
			int len = 0;
			while((len = is.read(bytes)) != -1){
				szout.write(bytes, 0, len);
			}
			is.close();
			szout.closeArchiveEntry();
		}else if(f.isDirectory()){
			String dirName = f.getName();
			if (".".equals(dirName)){
				dirName = "";
			}else{
				dirName += "/";
				ArchiveEntry entry = szout.createArchiveEntry(f, dir + dirName);
				szout.putArchiveEntry(entry);
				szout.closeArchiveEntry();
			}
			for(File file : f.listFiles()){
				sevenZCompressFile(szout, file, dir + dirName);
			}
		}
	}
	
	
	private static void unSevenZ(File sevenZFile, File destDir) throws IOException{
		unComperssByCompressInputStream(
				new SevenZInputStream(new SevenZFile(sevenZFile)), destDir);
	}
	private static void unZip(File zipFile, File destDir) throws IOException{
		unComperssByCompressInputStream(
				new ZipInputStream(new ZipArchiveInputStream(new FileInputStream(zipFile), "GBK")), destDir);
	}
	private static void unComperssByCompressInputStream(CompressInputStream cis, File destDir) throws IOException{
		try{
			CompressEntry entry = cis.getNextEntry();
			while(entry != null){
				File f = new File(destDir.getPath() + "/" + entry.getName());
				if (entry.isDirectory()){
					f.mkdirs();
				}else{
					f.getParentFile().mkdirs();
					OutputStream os = new FileOutputStream(f);
					IOUtils.copy(cis, os);
					os.close();
				}
				entry = cis.getNextEntry();
			}
		}catch(IOException e){
			new IOException(e);
		}finally{
			try{cis.close();}catch(Exception e){}
		}
	}
}
